#include "porting.h"

#include "sql_dump.h"
#include "sql_tree.h"
#include "sql_y.h"

#include <stdio.h>


int sql_print_hint (LN_STRING_PTR o, SQL_HINT_TYPE hint)
{
  static const char* name[] = 
  {
    ":ordered",
    ":recompile",
    ":join_nl",
    ":join_ind",
    ":join_merge",
    NULL
  };
  
  const char** p;

  for ( p = name; *p && hint > 0; p++, hint >>= 1 )
  {
    if ( hint & 1 )
    {
      sql_printf (o, *p);
    }
  }

  return 0;
};

int sql_print_name(LN_STRING_PTR s, struct SQL_node_name_t * name)
{
  while(name)
  {
    if (name->prefix)
      sql_printf ( s,"%s.%s", name->prefix , name->name);
    else
      sql_printf ( s,"%s", name->name);

    name = name->next;
    if (name)
    {
      sql_printf(s,";");
    }
  }
  return 0;
}

int SQL_node_dump_select (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep)
{
  struct SQL_node_select_t * v = &node->dt.select;

  /*
    SQL_HINT_TYPE hints;
    unsigned      distinct;
    SQL_NODE_PTR  spec_list;
    SQL_NODE_PTR  where_clause;
    SQL_NODE_PTR  select_list;

    SQL_NODE_PTR  order_by;
    SQL_NODE_PTR  group_by;
    SQL_NODE_PTR  having;
    SQL_NODE_PTR  to_param;
    SQL_NODE_PTR  using_index;*/
  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( s, "+%s(SELECT)",name);

  if ( v->hints )
  {
    sql_printf(s, " hint="      ); 
    sql_print_hint (s, v->hints);
  }

  if (v->distinct)
  {
    sql_printf (s, 
      v->distinct == SQL_ALL ? " all" :
      v->distinct == SQL_DISTINCT ? " distinct":
      v->distinct == SQL_UNIQUE   ? " unique" : "error" );
  }

  sql_printf(s,"\r\n");

  dep++;

  sql_dump_node (v->select_list, s, "select_list",dep);
  sql_dump_node (v->spec_list,   s, "spec_list"  ,dep);
  sql_dump_node (v->where_clause,s, "where"      ,dep);
  sql_dump_node (v->order_by,    s, "order_by"   ,dep);
  sql_dump_node (v->group_by,    s, "group_by"   ,dep);
  sql_dump_node (v->having,      s, "having"     ,dep);
  if (v->to_param)
  {
    sql_print_space (s,' ',dep + 1);
    sql_printf (s,"to_param(NAME_LIST):");
    sql_print_name (s, v->to_param);
    sql_printf (s,"\r\n");

  }
  sql_dump_node (v->using_index, s, "using_index",dep);

  return 0;
};

int SQL_node_dump_create_table (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep)
{
  struct SQL_node_create_table_t * v = &node->dt.create_table;

  /*
  struct SQL_node_name_t name;
  SQL_NODE_PTR  attr_def_list;
  unsigned int  hints;
*/

  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( s, "+%s(CREATE TABLE)",name);

  if ( v->hints )
  {
    sql_printf(s, " hint="      ); 
    sql_print_hint (s, v->hints);
  }
  
  sql_printf(s, "  table_name=");
  sql_print_name (s, v->name );
  sql_printf(s,"\r\n");
  
  sql_dump_node (v->attr_def_list,s,"def_list",dep + 1);
  sql_printf(s,"\r\n");

  return 0;
};

int SQL_node_dump_update (SQL_NODE_PTR node, LN_STRING_PTR s, const char* name, int dep)
{
  struct SQL_node_update_t * v = &node->dt.update;

  /*
  SQL_HINT_TYPE hints;
  SQL_NODE_PTR  table_name;
  const char*   as_id;
  SQL_NODE_PTR  update_list;
  SQL_NODE_PTR  where_clause;
  SQL_NODE_PTR  using_index;*/

  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( s, "+%s(UPDATE)",name);

  if ( v->hints )
  {
    sql_printf(s, " hint="      ); 
    sql_print_hint (s, v->hints);
  }
  
  sql_printf(s, "  table_name=");
  sql_print_name (s, v->table_name );
  
  if (v->as_id)
  {
    sql_printf(s, " as %s", v->as_id);  
  };

  sql_printf(s,"\r\n");

  dep++;

  sql_dump_node (v->update_list, s, "update_list",dep);
  sql_dump_node (v->where_clause,s, "where"      ,dep);
  sql_dump_node (v->using_index, s, "using_index",dep);

  return 0;
};

int SQL_node_dump_expr   (SQL_NODE_PTR node, LN_STRING_PTR s,  const char* name, int dep)
{
  struct SQL_node_expr_t * v = &node->dt.expr;

  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( 
    s, "+%s(EXPR) op=%s",
       name, 
       v->op >=0 && v->op < S_FUNC_TYPE_COUNT ? SQL_func_map[v->op].name : "not found" 
  );
  
  if (v->as_name)
  {
    sql_printf(s," as %s",v->as_name);
  };

  sql_printf ( s,"\r\n");

  sql_dump_node (v->p1, s, "P1", dep + 1);
  sql_dump_node (v->p2, s, "P2", dep + 1);
  sql_dump_node (v->p3, s, "P3", dep + 1);

  return 0;
};

int SQL_node_dump_list   (SQL_NODE_PTR node, LN_STRING_PTR s,  const char* name, int dep)
{
  struct SQL_node_list_t *v = &node->dt.list;
  struct SQL_node_link_t *i;

  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( s, "+%s(LIST)",name);
  sql_printf ( s,"\r\n");
  
  for ( i = v->head; i; i = i->next)
  {
    sql_dump_node ( i->data, s, "", dep + 1);
  }

  return 0;
};

int SQL_node_dump_spec (SQL_NODE_PTR node, LN_STRING_PTR s,  const char* name, int dep)
{
  struct SQL_node_table_spec_t *v = &node->dt.table_spec;
  
  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( s, "+%s(SPEC)",name);
  
  if (v->as_name)
  {
    sql_printf(s," as %s",v->as_name);
  };

  if (v->spec->type == S_NODE_NAME)
  {
    sql_printf(s,"name:");
    sql_print_name (s, & (v->spec->dt.name ) );
    sql_printf(s,"\r\n");
    return 0;
  };

  sql_printf ( s,"\r\n");
  sql_dump_node ( v->spec, s, "d-table", dep + 1);

  return 0;
};

int SQL_node_dump_field_def (SQL_NODE_PTR node, LN_STRING_PTR s,  const char* name, int dep)
{
  struct SQL_node_field_def_t *v = &node->dt.field_def;

  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( s, "+%s(FIELD_DEF) name=%-10s type=%2d,%4d,%4d\n",
    name,
    v->name, 
    (int)(v->type),
    (int)(v->type >> (16+32)),
    ( (int)(v->type >> 32) & 0xFFFF)
  );
  return 0;
}

int SQL_node_dump_name (SQL_NODE_PTR node, LN_STRING_PTR s,  const char* name, int dep)
{
  struct SQL_node_name_t *v = &node->dt.name;

  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( s, "+%s(NAME) name:",name);
  sql_print_name (s, v);
  sql_printf(s,"\r\n");

  return 0;
};

int SQL_node_dump_value (SQL_NODE_PTR node, LN_STRING_PTR s,  const char* name, int dep)
{
  LN_VARIANT_PTR v = &node->dt.value;

  sql_print_space ( s, ' ', dep * 2);
  sql_printf ( s, "+%s(VALUE)",name);
  
  switch (v->vt)
  {
    case LN_VT_INT32: sql_printf(s," type = int32, value=%d \r\n", v->dt.intval); break;
    case LN_VT_UINT32: sql_printf(s," type = uint32, value=%u \r\n", v->dt.intval); break;

    case LN_VT_INT64: sql_printf(s," type = int64, value=%llu \r\n", v->dt.i64val); break;
    case LN_VT_UINT64: sql_printf(s," type = uint64, value=%llu \r\n", v->dt.i64val); break;
    
    case LN_VT_DOUBLE : sql_printf(s, " type = double, value=%lf \r\n", v->dt.realval); break;
    default:
      {
        sql_printf (s, " unknown type %d\r\n",v->vt);
      }
  };

  return 0;
};

int sql_printf(LN_STRING_PTR o, const char* s, ...)
{
  va_list va;
  va_start (va, s);

  if ( o->buf_size < o->size + 128 )
  {
    if (o->buf_size == 0 )
    {
      o->val = (char*) malloc (o->buf_size + 256);
    }
    else
    {
      o->val = (char*) realloc (o->val, o->buf_size + 256);
    }

    o->buf_size += 256;
  };

  o->size += p_vsnprintf (o->val + o->size, 128, s, va);
  
  return 0;
};

int sql_print_space (LN_STRING_PTR o, int space, int count)
{
  char s[128];
  
  if ( count >0 && (count+1) < sizeof(s))
  {
    memset (s,' ', count);
    s[count] = 0;
    sql_printf (o, s);
  }

  return 0;
};